}
if (update_state) {
- if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0, 0))
+ if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0))
updated_IAs++;
syslog(LOG_INFO, "%s/%d preferred %d valid %d",
}
if (update_state) {
- if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0, 0))
+ if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0))
updated_IAs++;
syslog(LOG_INFO, "%s preferred %d valid %d",
}
bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
- uint32_t safe, unsigned int holdoff_interval)
+ unsigned int holdoff_interval)
{
struct odhcp6c_entry *x = odhcp6c_find_entry(state, new);
- uint32_t new_valid;
-
- /*
- * "safe" refers to https://www.rfc-editor.org/rfc/rfc4862#section-5.5.3
- * section e; it is either the two hours in seconds or zero when (e)
- * does not apply.
- *
- * The base condition for applying safe is that there is already a
- * matching prefix (and safe itself must be set).
- */
- if (safe && x) {
- if (new->valid > safe || new->valid > x->valid) {
- /*
- * 1: If the received Valid Lifetime is greater than 2 hours or
- * greater than RemainingLifetime, set the valid lifetime of the
- * corresponding address to the advertised Valid Lifetime.
- */
- new_valid = new->valid;
- } else if (x->valid <= safe) {
- /*
- * 2: If RemainingLifetime is less than or equal
- * to 2 hours, ignore the Prefix Information option with
- * regards to the valid lifetime, unless the Router
- * Advertisement from which this option was obtained has
- * been authenticated (e.g., via Secure Neighbor
- * Discovery [RFC3971]). If the Router Advertisement
- * was authenticated, the valid lifetime of the
- * corresponding address should be set to the Valid
- * Lifetime in the received option.
- *
- * Since authenticated advertisements aren't supported we
- * always keep the old value.
- */
- new_valid = x->valid;
- } else {
- /*
- * 3: Otherwise, reset the valid lifetime of the corresponding
- * address to 2 hours.
- */
- new_valid = safe;
- }
- } else {
- new_valid = new->valid;
- }
if (x) {
- if (holdoff_interval && new_valid >= x->valid &&
- new_valid != UINT32_MAX &&
- new_valid - x->valid < holdoff_interval &&
+ if (holdoff_interval && new->valid >= x->valid &&
+ new->valid != UINT32_MAX &&
+ new->valid - x->valid < holdoff_interval &&
new->preferred >= x->preferred &&
new->preferred != UINT32_MAX &&
new->preferred - x->preferred < holdoff_interval)
return false;
- x->valid = new_valid;
+ x->valid = new->valid;
x->preferred = new->preferred;
x->t1 = new->t1;
x->t2 = new->t2;
// Entry manipulation
bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
- uint32_t safe, unsigned int holdoff_interval);
+ unsigned int holdoff_interval);
void odhcp6c_expire(bool expire_ia_pd);
uint32_t odhcp6c_elapsed(void);
entry->valid = router_valid;
entry->preferred = entry->valid;
changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
- 0, ra_holdoff_interval);
+ ra_holdoff_interval);
// Parse hop limit
changed |= ra_set_hoplimit(adv->nd_ra_curhoplimit);
if (entry->priority > 0)
changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
- 0, ra_holdoff_interval);
+ ra_holdoff_interval);
} else if (opt->type == ND_OPT_PREFIX_INFORMATION && opt->len == 4) {
+ /*
+ * We implement draft-ietf-6man-slaac-renum-11 here:
+ * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-11#section-5.4
+ *
+ * This removes the two hour magic and instead just uses the new
+ * data. If the lifetime is zero, then the prefix is removed.
+ *
+ * An entry with lifetime zero is added. odhcp6c_expire will remove
+ * it again. odhcp6c_expire is called at the end of this function.
+ */
struct nd_opt_prefix_info *pinfo = (struct nd_opt_prefix_info*)opt;
entry->router = any;
entry->target = pinfo->nd_opt_pi_prefix;
if ((pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
!ptp_link)
changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
- 7200, ra_holdoff_interval);
+ ra_holdoff_interval);
if (!(pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) ||
pinfo->nd_opt_pi_prefix_len != 64)
entry->target.s6_addr32[3] = lladdr.s6_addr32[3];
changed |= odhcp6c_update_entry(STATE_RA_PREFIX, entry,
- 7200, ra_holdoff_interval);
+ ra_holdoff_interval);
} else if (opt->type == ND_OPT_RECURSIVE_DNS && opt->len > 2) {
entry->router = from.sin6_addr;
entry->priority = 0;
memcpy(&entry->target, &opt->data[6 + i * sizeof(entry->target)],
sizeof(entry->target));
changed |= odhcp6c_update_entry(STATE_RA_DNS, entry,
- 0, ra_holdoff_interval);
+ ra_holdoff_interval);
}
} else if (opt->type == ND_OPT_DNSSL && opt->len > 1) {
uint32_t *valid = (uint32_t*)&opt->data[2];
continue;
changed |= odhcp6c_update_entry(STATE_RA_SEARCH, entry,
- 0, ra_holdoff_interval);
+ ra_holdoff_interval);
entry->auxlen = 0;
}
}